/*
 * $Id: RscBundle.java,v 1.10 2004/10/06 20:03:17 jppietsch Exp $
 * Copyright (C) 2001 Jan-Peter Pietsch
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package de.jppietsch.util;

import de.jppietsch.error.Precondition;

import javax.swing.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.net.URL;
import java.util.ListResourceBundle;

/**
 * Convenient base class for resource bundles. It provides some convenience
 * methods to access resource bundles and to create non-text resources.
 *
 * @author Jan-Peter Pietsch
 * @version $Revision: 1.10 $
 */
public abstract class RscBundle extends ListResourceBundle {

    // constants

    /**
     * Suffix to build resource keys for text of buttons or menus.
     */
    public static final String NAME = ".actionName";

    public static final String SHORT = ".actionShortDescription";

    public static final String LONG = ".actionLongDescription";

    public static final String ICON = ".actionSmallIcon";

    public static final String CMD = ".actionCommand";

    public static final String ACCEL = ".actionAccelerator";

    public static final String MNEMO = ".actionMnemonic";

    /**
     * Convenience constant to avoid import of {@link KeyEvent}.
     */
    protected static final int F1 = KeyEvent.VK_F1;

    /**
     * Convenience constant to avoid import of {@link KeyEvent}.
     */
    protected static final int F2 = KeyEvent.VK_F2;

    /**
     * Convenience constant to avoid import of {@link KeyEvent}.
     */
    protected static final int F3 = KeyEvent.VK_F3;

    /**
     * Convenience constant to avoid import of {@link KeyEvent}.
     */
    protected static final int F4 = KeyEvent.VK_F4;

    /**
     * Convenience constant to avoid import of {@link KeyEvent}.
     */
    protected static final int F5 = KeyEvent.VK_F5;

    /**
     * Convenience constant to avoid import of {@link KeyEvent}.
     */
    protected static final int F6 = KeyEvent.VK_F6;

    /**
     * Convenience constant to avoid import of {@link KeyEvent}.
     */
    protected static final int F7 = KeyEvent.VK_F7;

    /**
     * Convenience constant to avoid import of {@link KeyEvent}.
     */
    protected static final int F8 = KeyEvent.VK_F8;

    /**
     * Convenience constant to avoid import of {@link KeyEvent}.
     */
    protected static final int F9 = KeyEvent.VK_F9;

    /**
     * Convenience constant to avoid import of {@link KeyEvent}.
     */
    protected static final int F10 = KeyEvent.VK_F10;

    /**
     * Convenience constant to avoid import of {@link KeyEvent}.
     */
    protected static final int F11 = KeyEvent.VK_F11;

    /**
     * Convenience constant to avoid import of {@link KeyEvent}.
     */
    protected static final int F12 = KeyEvent.VK_F12;

    /**
     * Convenience constant to avoid import of {@link KeyEvent}.
     */
    protected static final int DELETE = KeyEvent.VK_DELETE;

    /**
     * Convenience constant to avoid import of {@link KeyEvent}.
     */
    protected static final int INSERT = KeyEvent.VK_INSERT;

    // fields

    private Object[][] contents;

    // overwritten methods

    protected final Object[][] getContents() {
        if (contents == null) {
            contents = contents();
        }

        return contents;
    }

    // public methods

    public static RscBundle getBundle(Class aResourceBundleClass) {
        return (RscBundle) getBundle(aResourceBundleClass.getName());
    }

    /**
     * Returns a resource for a name of a button or menu.
     *
     * @param aKeyPrefix from which the resource key is constructed by appending
     *                   {@link #NAME}.
     * @return The localized name.
     * @throws java.util.MissingResourceException
     *          If there is no such resource.
     */
    public String getName(String aKeyPrefix) {
        return getString(aKeyPrefix + NAME);
    }

    /**
     * Returns a localized mnemonic.
     *
     * @param aKeyPrefix from which the resource key is constructed by appending
     *                   {@link #MNEMO}.
     * @return The localized mnemonic.
     * @throws java.util.MissingResourceException
     *          If there is no such resource.
     */
    public int getMnemonic(String aKeyPrefix) {
        return ((Integer) getObject(aKeyPrefix + MNEMO)).intValue();
    }

    // protected methods

    protected Icon icon(String aPngName) {
        Precondition.argumentStringNotEmpty("aPngName", aPngName);
        Class cls = getClass();
        String nam = cls.getName();
        int idx = nam.lastIndexOf('.');
        String dir = idx < 0 ? "" : nam.substring(0, idx + 1).replace('.', '/');
        String rsc = dir + aPngName + ".png";
        URL url = cls.getClassLoader().getResource(rsc);

        //assert url!=null: "Image \""+rsc+"\" is missing!";

        return new ImageIcon(url);
    }

    /**
     * Creates a key stroke which represents a control-key character.
     *
     * @param aCharacter to be pressed together with control.
     * @return The resulting key stroke.
     */
    protected static KeyStroke accel(char aCharacter) {
        return KeyStroke
                .getKeyStroke(keyCode(aCharacter), InputEvent.CTRL_MASK);
    }

    /**
     * Creates a control key stroke..
     *
     * @param aKeyCode A key code like {@link #F1}or {@link #INSERT}.
     * @return The resulting key stroke.
     */
    protected static KeyStroke ctrlAccel(int aKeyCode) {
        return KeyStroke.getKeyStroke(aKeyCode, InputEvent.CTRL_MASK);
    }

    /**
     * Creates an alted key stroke..
     *
     * @param aKeyCode A key code like {@link #F1}or {@link #INSERT}.
     * @return The resulting key stroke.
     */
    protected static KeyStroke altAccel(int aKeyCode) {
        return KeyStroke.getKeyStroke(aKeyCode, InputEvent.ALT_MASK);
    }

    /**
     * Creates a shifted key stroke..
     *
     * @param aKeyCode A key code like {@link #F1}or {@link #INSERT}.
     * @return The resulting key stroke.
     */
    protected static KeyStroke shiftAccel(int aKeyCode) {
        return KeyStroke.getKeyStroke(aKeyCode, InputEvent.SHIFT_MASK);
    }

    protected static Integer mnemo(char aCharacter) {
        return new Integer(keyCode(aCharacter));
    }

    protected abstract Object[][] contents();

    // private methods

    private static int keyCode(char aCharacter) {
        Precondition.argumentValid("aCharacter", aCharacter, '0' <= aCharacter
                && aCharacter <= '9' || 'A' <= aCharacter && aCharacter <= 'Z'
                || 'a' <= aCharacter && aCharacter <= 'z');

        return Character.toUpperCase(aCharacter);
    }

}